package me.zhengjie.tool;

import com.google.common.collect.Maps;


import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;

@SuppressWarnings({"rawtypes", "unchecked"})
public class MapUtil implements Serializable {

    private static final long serialVersionUID = -3576658188605077086L;

    public static void addMapToOtherMap(Map<String, List<Map>> restultMap, Map<String, List<Map>> map) {
        Iterator i = map.entrySet().iterator();
        while (i.hasNext()) {
            Entry entry = (Entry) i.next();
            String key = (String) entry.getKey();
            List<Map> list = (List) entry.getValue();
            if (restultMap.containsKey(key)) {
                List<Map> restultList = restultMap.get(key);
                restultList.addAll(list);
                restultMap.put(key, restultList);
            } else {
                restultMap.put(key, list);
            }
        }
    }

    public static void addListToMap(Map<String, List<Map>> restultMap, String sqlID, List<Map> list) {
        Map<String, List<Map>> newMap = new HashMap<>();
        newMap.put(sqlID, list);
        addMapToOtherMap(restultMap, newMap);
    }


    private static Map toMap(Class c, Object o) {
        Map map = new HashMap();
        Field[] fields = c.getDeclaredFields();
        String getMethod;
        Method fieldSetMet;
        Object out;
        for (Field field : fields) {
            if ("serialVersionUID".equals(field.getName())) {
                continue;
            }
            getMethod = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
            try {
                fieldSetMet = c.getMethod(getMethod);
                out = fieldSetMet.invoke(o);
            } catch (Exception e) {
                throw new IllegalArgumentException(e.getMessage());
            }
            if (!ValidateUtil.isEmpty(out)) {
                map.put(field.getName(), out);
            }
        }
		/*if(!ValidateUtil.isEmpty(c.getSuperclass())){
			map.putAll(toMap(c.getSuperclass(), o));
		}*/
        return map;
    }

    public static Map toMap(Object o) {
        return toMap(o.getClass(), o);
    }

    public static void toVO(Object o, Map dto) throws Exception {
        Class c = o.getClass();
        Field[] fields = c.getDeclaredFields();
        String getMethod;
        Method fieldSetMet;
        Class[] param;
        for (Field field : fields) {
            param = new Class[1];
            getMethod = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
            param[0] = field.getType();
            fieldSetMet = c.getMethod(getMethod, param);
            if (!ValidateUtil.isEmpty(dto.get(field.getName()))) {
                fieldSetMet.invoke(o, dto.get(field.getName()));
            }
        }
    }

    /**
     * list转换成map
     *
     * @param list 需要转换成map的列表，列表中只能包含Map
     * @param pks  可由list的多个字段组合成一个string来作为键值，可传入格式：  字段1,字段2,字段3
     * @return
     * @throws Exception
     * @author tianqi
     * @datetime 2016年8月19日 下午5:51:59
     * @version 1.0
     * @see
     */
    public static Map list2map(List list, String pks) throws Exception {
        Map<String, Map> resultMap = Maps.newHashMap();
        List pkList = ListUtil.string2List(pks, ",");
        String mapKey = "";
        for (Iterator iterator = list.iterator(); iterator.hasNext(); ) {
            Map m = (Map) iterator.next();
            mapKey = "";
            for (Iterator iterator2 = pkList.iterator(); iterator2.hasNext(); ) {
                String pk = (String) iterator2.next();
                if (!ValidateUtil.isEmpty(m.get(pk))) {
                    mapKey = mapKey + m.get(pk);
                }
            }
            resultMap.put(mapKey, m);
        }
        return resultMap;
    }

    /**
     * 将String按照对应标准转换为Map
     *
     * @param value
     * @param key
     * @return
     * @throws Exception
     */
    public static Map<String, String> toMapForString(String value, String key) throws Exception {
        Map<String, String> map = new HashMap<>();
        String[] values = value.split(",");
        String[] keys = key.split(",");
        for (int i = 0; i < keys.length; i++) {
            map.put(keys[i], values[i]);
        }
        return map;
    }

    /**
     * 移除map中空key或者value空值
     * @param map
     */
    public static void removeNullEntry(Map map){
        removeNullKey(map);
        removeNullValue(map);
    }
    /**
     * 移除map的空key
     * @param map
     * @return
     */
    public static void removeNullKey(Map map){
        Set set = map.keySet();
        for (Iterator iterator = set.iterator(); iterator.hasNext();) {
            Object obj = (Object) iterator.next();
            remove(obj, iterator);
        }
    }



    /**
     * 移除map中的value空值
     * @param map
     * @return
     */
    public static void removeNullValue(Map map){
        Set set = map.keySet();
        for (Iterator iterator = set.iterator(); iterator.hasNext();) {
            Object obj = (Object) iterator.next();
            Object value =(Object)map.get(obj);
            remove(value, iterator);
        }
    }
    /**
     * 移除map中的空值
     *
     * Iterator 是工作在一个独立的线程中，并且拥有一个 mutex 锁。
     * Iterator 被创建之后会建立一个指向原来对象的单链索引表，当原来的对象数量发生变化时，这个索引表的内容不会同步改变，
     * 所以当索引指针往后移动的时候就找不到要迭代的对象，所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
     * 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。
     * 但你可以使用 Iterator 本身的方法 remove() 来删除对象， Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。
     * @param obj
     * @param iterator
     */
    private static void remove(Object obj,Iterator iterator){
        if(obj instanceof String){
            String str = (String)obj;
            if(isEmpty(str)){ //过滤掉为null和""的值 主函数输出结果map：{2=BB, 1=AA, 5=CC, 8= }
//      if("".equals(str.trim())){ //过滤掉为null、""和" "的值 主函数输出结果map：{2=BB, 1=AA, 5=CC}
                iterator.remove();
            }
        }else if(obj instanceof Collection){
            Collection col = (Collection)obj;
            if(col==null||col.isEmpty()){
                iterator.remove();
            }
        }else if(obj instanceof Map){
            Map temp = (Map)obj;
            if(temp==null||temp.isEmpty()){
                iterator.remove();
            }
        }else if(obj instanceof Object[]){
            Object[] array =(Object[])obj;
            if(array==null||array.length<=0){
                iterator.remove();
            }
        }else{
            if(obj==null){
                iterator.remove();
            }
        }
    }
    public static boolean isEmpty(Object obj){
        return ValidateUtil.isEmpty(obj);
    }
    /**
     * 去除Map中value 为空的数据
     * @Param onlyNull 是否只删除空指针，避免数据结构被破坏，建议true
     * @Param map 源map
     * */
    public static void removeNull(Map srcMap,boolean onlyNull){
        Iterator iterator = srcMap.entrySet().iterator();
        while (iterator.hasNext()){
            Object valueTmp = null;
            Entry next = (Entry)iterator.next();
            if ((valueTmp = next.getValue()) == null){
                iterator.remove();
            }
            if (onlyNull){
                continue;
            }
            else if (valueTmp instanceof String){
                String str = (String) valueTmp;
                if (str.isEmpty()) {
                    iterator.remove();
                }
            }
            // 集合需要深度遍历
            else if (valueTmp instanceof Collection){
                Collection str = (Collection) valueTmp;
                if (str.isEmpty()) {
                    iterator.remove();
                }
            }
            else if (valueTmp instanceof Map){
                Map tmpMap = (Map)valueTmp;
                if (tmpMap.isEmpty()){
                    iterator.remove();
                }
            }
        }
    }
    public static void assignMap(Map srcMap,Map descMap){
        removeNull(descMap,true);
        srcMap.putAll(descMap);
    }
    /**
     * 获取map中各项之和*/
    public static BigDecimal getSumFromMap(Map map,String keyStr){
        String[] keys = keyStr.split(",");
        BigDecimal sum = new BigDecimal("0");
        for (String key : keys) {
            Object tmp = map.get(key);
            if (tmp == null){
                continue;
            }
            else if (tmp instanceof BigDecimal){
                sum = sum.add((BigDecimal) tmp);
                continue;
            }
            else if (tmp instanceof Number){
                sum = sum.add(BigDecimal.valueOf(((Number) tmp).doubleValue()));
            }
            else {
                BigDecimal elseType;
                try {
                    elseType = new BigDecimal(tmp.toString());
                    sum = sum.add(elseType);
                }catch (Exception e){
//                    elseType = BigDecimal.ZERO;
                }

            }
        }
        return sum;
    }

}
